import Singleton from "../base/Singleton";

interface IItem {
    func: Function
    ctx: unknown
}

export default class EventManager extends Singleton {

    static get Instance() {
        return super.GetInstance<EventManager>();
    }

    private eventDic: Map<string, Array<IItem>> = new Map()

    /**
     * 注册
     * @param eventName 事件名称 
     * @param func 回调方法
     * @param ctx  上下文
     */
    on(eventName: string, func: Function, ctx: Object) {
        if (this.eventDic.has(eventName)) {
            this.eventDic.get(eventName).push({ func, ctx })
        } else {
            this.eventDic.set(eventName, [{ func, ctx }])
        }
    }

    /**
     * 注销
     * @param eventName 事件名称 
     * @param ctx 上下文
     */
    off(eventName: string, ctx: Object) {
        if (this.eventDic.has(eventName)) {
            const index = this.eventDic.get(eventName).findIndex(i => i.ctx === ctx)
            index > -1 && this.eventDic.get(eventName).splice(index, 1)
        }
    }

    /**
     * 注册(只执行一次)
     * @param eventName 
     * @param func 
     * @param ctx 
     */
    once(eventName: string, func: Function, ctx: Object) {
        let _listener: Function | null = ($event: string, $args: any) => {
            this.off(eventName, ctx);
            _listener = null;
            func.call(ctx, $event, $args);
        };
        this.on(eventName, _listener, ctx);
    }

    /**
     * 触发事件
     * @param eventName 事件名称
     * @param params 参数
     */
    emit(eventName: string, ...params: unknown[]) {
        if (this.eventDic.has(eventName)) {
            this.eventDic.get(eventName).forEach(({ func, ctx }) => {
                ctx ? func.apply(ctx, params) : func(...params)
            })
        }
    }

    /**
     * 清空
     */
    clear() {
        this.eventDic.clear()
    }

}